home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / Main.bin / ObjectStreamClass.java < prev    next >
Text File  |  1998-09-22  |  27KB  |  859 lines

  1. /*
  2.  * @(#)ObjectStreamClass.java    1.41 98/07/09
  3.  *
  4.  * Copyright 1995-1998 by Sun Microsystems, Inc.,
  5.  * 901 San Antonio Road, Palo Alto, California, 94303, U.S.A.
  6.  * All rights reserved.
  7.  * 
  8.  * This software is the confidential and proprietary information
  9.  * of Sun Microsystems, Inc. ("Confidential Information").  You
  10.  * shall not disclose such Confidential Information and shall use
  11.  * it only in accordance with the terms of the license agreement
  12.  * you entered into with Sun.
  13.  */
  14.  
  15. package java.io;
  16.  
  17. import sun.misc.Ref;
  18. import java.security.MessageDigest;
  19. import java.security.NoSuchAlgorithmException;
  20. import java.security.DigestOutputStream;
  21. import java.lang.reflect.Modifier;
  22.  
  23. /**
  24.  * A ObjectStreamClass describes a class that can be serialized to a stream
  25.  * or a class that was serialized to a stream.  It contains the name
  26.  * and the serialVersionUID of the class.
  27.  * <br>
  28.  * The ObjectStreamClass for a specific class loaded in this Java VM can
  29.  * be found using the lookup method.
  30.  *
  31.  * @author  unascribed
  32.  * @version 1.41, 07/09/98
  33.  * @since   JDK1.1
  34.  */
  35. public class ObjectStreamClass implements java.io.Serializable {
  36.  
  37.    static final long serialVersionUID = -6120832682080437368L;
  38.  
  39.    /** Find the descriptor for a class that can be serialized.  Null
  40.      * is returned if the specified class does not implement
  41.      * java.io.Serializable or java.io.Externalizable.
  42.      * @since   JDK1.1
  43.      */
  44.     public static ObjectStreamClass lookup(Class cl)
  45.     {
  46.     /* Synchronize on the hashtable so no two threads will do
  47.      * this at the same time.
  48.      */
  49.     ObjectStreamClass v = null;
  50.     synchronized (descriptorFor) {
  51.         /* Find the matching descriptor if it already known */
  52.         v = findDescriptorFor(cl);
  53.         if (v != null) {
  54.         return v;
  55.         }
  56.         
  57.         /* Check if it's serializable or externalizable.
  58.          * Since Externalizable extends Serializiable, return
  59.          * null immediately if it's not Serializable.
  60.          */
  61.         boolean serializable = classSerializable.isAssignableFrom(cl);
  62.         if (!serializable)
  63.         return null;
  64.  
  65.         /* Test if it's Externalizable, clear the serializable flag
  66.          * only one or the other may be set in the protocol.
  67.          */
  68.         boolean externalizable = classExternalizable.isAssignableFrom(cl);
  69.         if (externalizable)
  70.         serializable = false;
  71.  
  72.         /* If the class is only Serializable,
  73.          * lookup the descriptor for the superclass.
  74.          */
  75.         ObjectStreamClass superdesc = null;
  76.         if (serializable) {
  77.         Class superclass = cl.getSuperclass();
  78.         if (superclass != null) 
  79.             superdesc = lookup(superclass);
  80.         }
  81.  
  82.         /* Create a new version descriptor,
  83.          * it put itself in the known table.
  84.          */
  85.         v = new ObjectStreamClass(cl, superdesc,
  86.                       serializable, externalizable);
  87.     }
  88.     return v;
  89.     }
  90.     
  91.     /**
  92.      * The name of the class described by this descriptor.
  93.      * @since   JDK1.1
  94.      */
  95.     public String getName() {
  96.     return name;
  97.     }
  98.  
  99.     /**
  100.      * Return the serialVersionUID for this class.
  101.      * The serialVersionUID defines a set of classes all with the same name
  102.      * that have evolved from a common root class and agree to be serialized
  103.      * and deserialized using a common format.
  104.      * @since   JDK1.1
  105.      */
  106.     public long getSerialVersionUID() {
  107.     return suid;
  108.     }
  109.  
  110.     /**
  111.      * Return the class in the local VM that this version is mapped to.
  112.      * Null is returned if there is no corresponding local class.
  113.      * @since   JDK1.1
  114.      */
  115.     public Class forClass() {
  116.     return ofClass;
  117.     }
  118.     
  119.     /**
  120.      * Return a string describing this ObjectStreamClass.
  121.      * @since   JDK1.1
  122.      */
  123.     public String toString() {
  124.     StringBuffer sb = new StringBuffer();
  125.  
  126.     sb.append(name);
  127.     sb.append(": static final long serialVersionUID = ");
  128.     sb.append(Long.toString(suid));
  129.     sb.append("L;");
  130.     return sb.toString();
  131.     }
  132.  
  133.     /*
  134.      * Create a new ObjectStreamClass from a loaded class.
  135.      * Don't call this directly, call lookup instead.
  136.      */
  137.     private ObjectStreamClass(java.lang.Class cl, ObjectStreamClass superdesc,
  138.                   boolean serial, boolean extern)
  139.     {
  140.     int i;
  141.     ofClass = cl;        /* created from this class */
  142.  
  143.     name = cl.getName();
  144.     superclass = superdesc;
  145.     serializable = serial;
  146.     externalizable = extern;
  147.  
  148.     /*
  149.      * Enter this class in the table of known descriptors.
  150.      * Otherwise, when the fields are read it may recurse
  151.      * trying to find the descriptor for itself.
  152.      */
  153.     insertDescriptorFor(this);
  154.  
  155.     if (externalizable || name.equals("java.lang.String")) {
  156.         fields = new ObjectStreamField[0];
  157.     } else {
  158.         /* Fill in the list of persistent fields. */
  159.         fields = getFields0(cl);
  160.  
  161.         if (fields.length > 0) {
  162.         /* sort the fields by type and name,
  163.          * primitive fields come first, sorted by name,
  164.          * then object fields, sorted by name.
  165.          */
  166.         boolean done;
  167.         do {
  168.             done = true;
  169.             for (i = fields.length - 1 ; i > 0 ; i--) {
  170.             if (fields[i - 1].compare(fields[i]) > 0) {
  171.                 ObjectStreamField exch = fields[i];
  172.                 fields[i] = fields[i-1];
  173.                 fields[i-1] = exch;
  174.                 done = false;
  175.             }
  176.             }
  177.         } while (!done);
  178.  
  179.         computeFieldSequence();
  180.         }
  181.     }
  182.  
  183.     /* Get the serialVersionUID from the class */
  184.     suid = getSerialVersionUID(cl);
  185.     if (suid == 0) {
  186.         suid = computeSerialVersionUID(cl);
  187.     }
  188.     hasWriteObjectMethod = externalizable ? false : hasWriteObject(cl);
  189.     }
  190.  
  191.     /*
  192.      * Create an empty ObjectStreamClass for a class about to be read.
  193.      * This is separate from read so ObjectInputStream can assign the
  194.      * wire handle early, before any nested ObjectStreamClasss might
  195.      * be read.
  196.      */
  197.     ObjectStreamClass(String n, long s) {
  198.     name = n;
  199.     suid = s;
  200.     superclass = null;
  201.     }
  202.  
  203.     /*
  204.      * Set the class this version descriptor matches.
  205.      * The name and serializable hash  must match.
  206.      * Compute and fill in the fieldSequence that will be used
  207.      * for reading.
  208.      */
  209.     void setClass(Class cl) throws InvalidClassException {
  210.     if (cl == null) {
  211.  
  212.         /* There is no local equivalent of this class read from the serialized
  213.          * stream. Initialize this class to always discard data associated with
  214.          * this class.
  215.          */
  216.         localClassDesc = null;
  217.         ofClass = null;
  218.         for (int i = 0; i < fields.length; i++ ) {
  219.         fields[i].offset = -1; // discard data read from stream.
  220.         }
  221.         computeFieldSequence();
  222.         return;
  223.     }
  224.  
  225.     localClassDesc = lookup(cl);
  226.  
  227.     if (localClassDesc == null)
  228.         throw new InvalidClassException(cl.getName(), 
  229.                         "Local class not compatible");
  230.  
  231.     if (suid != localClassDesc.suid) {
  232.         
  233.         /* Disregard the serialVersionUID of an array
  234.          * when name and cl.Name differ. If resolveClass() returns
  235.          * an array with a different package name,
  236.          * the serialVersionUIDs will not match since the fully
  237.          * qualified array class is used in the
  238.          * computation of the array's serialVersionUID. There is
  239.          * no way to set a permanent serialVersionUID for an array type.
  240.          */
  241.         if (! (cl.isArray() && ! cl.getName().equals(name)))
  242.         throw new InvalidClassException(cl.getName(), 
  243.             "Local class not compatible:" + 
  244.             " stream classdesc serialVersionUID=" + suid +
  245.             " local class serialVersionUID=" + localClassDesc.suid);
  246.     }
  247.  
  248.     if (! compareClassNames(name, cl.getName(), '.'))
  249.         throw new InvalidClassException(name,
  250.                         "Incompatible local class name: " +
  251.                         cl.getName());
  252.  
  253.     /*
  254.      * Test that both implement either serializable or externalizable.
  255.      */
  256.     if (serializable != localClassDesc.serializable ||
  257.         externalizable != localClassDesc.externalizable)
  258.         throw new InvalidClassException(cl.getName(),
  259.                     "Serialization incompatible with Externalization");
  260.  
  261.     /* Compute the offsets in the class where each field in this descriptor
  262.      * should be stored.  The fieldSequence is computed from the offsets
  263.      * and used by the native code to read and store the values.
  264.      * Each field in this ObjectStreamClass (the source) is located (by name) in
  265.      * the ObjectStreamClass of the class(the destination).
  266.      * In the usual (non-versioned case) the field is in both
  267.      * descriptors and the types match, so the offset is copied.
  268.      * If the type does not match, a InvalidClass exception is thrown.
  269.      * If the field is not present in the class, the offset is set to -1
  270.      * so the field will be read but discarded.
  271.      * If extra fields are present in the class they are ignored. Their
  272.      * values will be set to the default value by the object allocator.
  273.      * Both the src and dest field list are sorted by type and name.
  274.      */
  275.  
  276.     ObjectStreamField[] destfield = localClassDesc.getFields();
  277.     ObjectStreamField[] srcfield = fields;
  278.  
  279.     int j = 0;
  280.     nextsrc:
  281.     for (int i = 0; i < srcfield.length; i++ ) {
  282.         /* Find this field in the dest*/
  283.         for (int k = j; k < destfield.length; k++) {
  284.           if (srcfield[i].name.equals(destfield[k].name)) {
  285.           /* found match */
  286.           if (!srcfield[i].typeEquals(destfield[k])) {
  287.               throw new InvalidClassException(cl.getName(),
  288.                           "The type of field " +
  289.                                srcfield[i].name +
  290.                                " of class " + name +
  291.                                " is incompatible.");
  292.           }
  293.  
  294.           /* Skip over any fields in the dest that are not in the src */
  295.            j = k; 
  296.           
  297.           srcfield[i].offset = destfield[j].offset;
  298.           // go on to the next source field
  299.           continue nextsrc;
  300.           }
  301.         }
  302.         /* Source field not found in dest, mark field to discard. */
  303.         srcfield[i].offset = -1;
  304.     }
  305.  
  306.     /* Setup the field sequence for native code */
  307.     computeFieldSequence();
  308.  
  309.     /* Remember the class this represents */
  310.     ofClass = cl;
  311.     }
  312.  
  313.     /* Compare the base class names of streamName and localName.
  314.      * 
  315.      * @return  Return true iff the base class name compare.
  316.      * @parameter streamName    Fully qualified class name.
  317.      * @parameter localName    Fully qualified class name.
  318.      * @parameter pkgSeparator    class names use either '.' or '/'.
  319.      * 
  320.      * Only compare base class name to allow package renaming.
  321.      */
  322.     static boolean compareClassNames(String streamName,
  323.                      String localName,
  324.                      char pkgSeparator) {
  325.     /* compare the class names, stripping off package names. */
  326.     int streamNameIndex = streamName.lastIndexOf(pkgSeparator);
  327.     if (streamNameIndex < 0) 
  328.         streamNameIndex = 0;
  329.  
  330.     int localNameIndex = localName.lastIndexOf(pkgSeparator);
  331.     if (localNameIndex < 0)
  332.         localNameIndex = 0;
  333.  
  334.     boolean result = streamName.regionMatches(false, streamNameIndex, 
  335.                     localName, localNameIndex,
  336.                     streamName.length() - streamNameIndex);
  337.     return result;
  338.     }
  339.  
  340.     /*
  341.      * Compare the types of two class descriptors.
  342.      * They match if they have the same class name and suid
  343.      */
  344.     boolean typeEquals(ObjectStreamClass other) {
  345.     return (suid == other.suid) &&
  346.         compareClassNames(name, other.name, '.');
  347.     }
  348.     
  349.     /*
  350.      * Return the array of persistent fields for this class.
  351.      */
  352.     ObjectStreamField[] getFields(){
  353.     return fields;
  354.     }
  355.     
  356.     /*
  357.      * Return the superclass descriptor of this descriptor.
  358.      */
  359.     void setSuperclass(ObjectStreamClass s) {
  360.     superclass = s;
  361.     }
  362.  
  363.     /*
  364.      * Return the superclass descriptor of this descriptor.
  365.      */
  366.     ObjectStreamClass getSuperclass() {
  367.     return superclass;
  368.     }
  369.     
  370.     /*
  371.      * Return whether the class has a writeObject method
  372.      */
  373.     boolean hasWriteObject() {
  374.     return hasWriteObjectMethod;
  375.     }
  376.     
  377.     /*
  378.      * Return true if 'this' Externalizable class was written in block data mode.
  379.      * Maintain forwards compatibility for JDK 1.1 streams containing non-block data
  380.      * mode externalizable data.
  381.      *
  382.      * @since JDK 1.1.6
  383.      */
  384.     boolean hasExternalizableBlockDataMode() {
  385.     return hasExternalizableBlockData;
  386.     }
  387.  
  388.     /*
  389.      * Return the ObjectStreamClass of the local class this one is based on.
  390.      */
  391.     ObjectStreamClass localClassDescriptor() {
  392.     return localClassDesc;
  393.     }
  394.     
  395.     /*
  396.      * Get the externalizability of the class.
  397.      */
  398.     boolean isExternalizable() {
  399.     return externalizable;
  400.     }
  401.  
  402.     /*
  403.      * Get the sequence of fields for this Class.
  404.      */
  405.     int[] getFieldSequence() {
  406.     return fieldSequence;
  407.     }
  408.  
  409.     /*
  410.      * Create the array used by the native code containing
  411.      * the types and offsets to store value read from the stream.
  412.      * The array is an array of int's with the even numbered elements
  413.      * containing the type (first character) and the odd elements
  414.      * containing the offset into the object where the value should be
  415.      * stored.  An offset of -1 means the value should be discarded.
  416.      */
  417.     private void computeFieldSequence() {
  418.     fieldSequence = new int[fields.length*2];
  419.     for (int i = 0; i < fields.length; i++ ) {
  420.         fieldSequence[i*2] = fields[i].type;
  421.         fieldSequence[i*2+1] = fields[i].offset;
  422.     }
  423.     }
  424.     
  425.     /*
  426.      * Compute a hash for the specified class.  Incrementally add
  427.      * items to the hash accumulating in the digest stream.
  428.      * Fold the hash into a long.  Use the SHA secure hash function.
  429.      */
  430.     private static long computeSerialVersionUID(Class thisclass) {
  431.     ByteArrayOutputStream devnull = new ByteArrayOutputStream(512);
  432.  
  433.     long h = 0;
  434.     try {
  435.         MessageDigest md = MessageDigest.getInstance("SHA");
  436.         DigestOutputStream mdo = new DigestOutputStream(devnull, md);
  437.         DataOutputStream data = new DataOutputStream(mdo);
  438.  
  439.         data.writeUTF(thisclass.getName());
  440.         
  441.         int classaccess = getClassAccess(thisclass);
  442.         classaccess &= (Modifier.PUBLIC | Modifier.FINAL |
  443.                 Modifier.INTERFACE | Modifier.ABSTRACT);
  444.         data.writeInt(classaccess);
  445.         
  446.         /* 
  447.          * Get the list of interfaces supported,
  448.          * Accumulate their names their names in Lexical order
  449.          * and add them to the hash
  450.          */
  451.         Class interfaces[] = thisclass.getInterfaces();
  452.         quicksort(interfaces);
  453.         
  454.         for (int i = 0; i < interfaces.length; i++) {
  455.         data.writeUTF(interfaces[i].getName());
  456.         }
  457.  
  458.         /* Sort the field names to get a deterministic order */
  459.         String fields[] = getFieldSignatures(thisclass);
  460.         quicksort(fields);
  461.         
  462.         /* Include in the hash all fields except those that are
  463.          * private transient and private static.
  464.          */
  465.         for (int i = 0; i < fields.length; i++) {
  466.         String field = fields[i];
  467.         int access = getFieldAccess(thisclass, field);
  468.         if ((access & M_PRIVATE) == M_PRIVATE &&
  469.             (((access & M_TRANSIENT) == M_TRANSIENT)||
  470.              ((access & M_STATIC) == M_STATIC)))
  471.             continue;
  472.         int offset = field.indexOf(' ');
  473.         String name = field.substring(0, offset);
  474.         String desc = field.substring(offset+1);
  475.         data.writeUTF(name);
  476.         data.writeInt(access);
  477.         data.writeUTF(desc);
  478.         }
  479.  
  480.         /*
  481.          * Get the list of methods including name and signature
  482.          * Sort lexically, add all except the private methods
  483.          * to the hash with their access flags
  484.          */
  485.         String methods[] = getMethodSignatures(thisclass);
  486.         quicksort(methods);
  487.         
  488.         for (int i = 0; i < methods.length; i++) {
  489.         String method = methods[i];
  490.         int access = getMethodAccess(thisclass, method);
  491.         if ((access & M_PRIVATE) != 0)
  492.             continue;
  493.         int offset = method.indexOf(' ');
  494.         String mname = method.substring(0, offset);
  495.         String desc = method.substring(offset+1);
  496.         desc = desc.replace('/', '.');
  497.         data.writeUTF(mname);
  498.         data.writeInt(access);
  499.         data.writeUTF(desc);
  500.         }
  501.  
  502.         /* Compute the hash value for this class.
  503.          * Use only the first 64 bits of the hash.
  504.          */
  505.         byte hasharray[] = md.digest();
  506.         for (int i = 0; i < Math.min(8, hasharray.length); i++) {
  507.         h += (long)(hasharray[i] & 255) << (i * 8);
  508.         }
  509.     } catch (IOException ignore) {
  510.         /* can't happen, but be deterministic anyway. */
  511.         h = -1;
  512.     } catch (NoSuchAlgorithmException complain) {
  513.         throw new SecurityException(complain.getMessage());
  514.     }
  515.     return h;
  516.     }
  517.  
  518.     /* These are in this class so that there is no chance they can be used
  519.      * outside the class.
  520.      */
  521.     private static native int getClassAccess(Class aclass);
  522.  
  523.     private static native String[] getMethodSignatures(Class aclass);
  524.     private static native int getMethodAccess(Class aclass, String methodsig);
  525.  
  526.     private static native String[] getFieldSignatures(Class aclass);
  527.     private static native int getFieldAccess(Class aclass, String fieldsig);
  528.  
  529.     private static final int M_TRANSIENT = 0x0080;
  530.     private static final int M_PRIVATE = 0x0002;
  531.     private static final int M_STATIC = 0x0008;
  532.  
  533.     /*
  534.      * locate the ObjectStreamClass for this class and write it to the stream.
  535.      */
  536.     void write(ObjectOutputStream s) throws IOException {
  537.     
  538.     /* write the flag indicating that this class has write/read object methods */
  539.     int flags = 0;
  540.     if (hasWriteObjectMethod)
  541.         flags |= ObjectStreamConstants.SC_WRITE_METHOD;
  542.     if (serializable)
  543.         flags |= ObjectStreamConstants.SC_SERIALIZABLE;
  544.     if (externalizable)
  545.         flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
  546.     s.writeByte(flags);
  547.     
  548.     /* write the total number of fields */
  549.     s.writeShort(fields.length);
  550.     
  551.     /* Write out the descriptors of the primitive fields Each
  552.      * descriptor consists of the UTF fieldname, a short for the
  553.      * access modes, and the first byte of the signature byte.
  554.      * For the object types, ('[' and 'L'), a reference to the
  555.      * type of the field follows.
  556.      */
  557.  
  558.     /* disable replacement of String objects written
  559.      * by ObjectStreamClass. */
  560.     boolean prevReplaceObject = s.enableReplace;
  561.     s.enableReplace = false;
  562.     try {
  563.         for (int i = 0; i < fields.length; i++ ) {
  564.         ObjectStreamField f = fields[i];
  565.         s.writeByte(f.type);
  566.         s.writeUTF(f.name);
  567.         if (!f.isPrimitive()) {
  568.             s.writeObject(f.typeString);
  569.         }
  570.         }
  571.     } finally {
  572.         s.enableReplace = prevReplaceObject;
  573.     }
  574.     }
  575.  
  576.  
  577.     /*
  578.      * Read the version descriptor from the stream.
  579.      * Write the count of field descriptors
  580.      * for each descriptor write the first character of its type,
  581.      * the name of the field.
  582.      * If the type is for an object either array or object, write
  583.      * the type typedescriptor for the type
  584.      */
  585.     void read(ObjectInputStream s) throws IOException, ClassNotFoundException {
  586.     
  587.     /* read flags and determine whether the source class had
  588.          * write/read methods.
  589.      */
  590.     byte flags = s.readByte();
  591.  
  592.     serializable = (flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0;
  593.     externalizable = (flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0;
  594.  
  595.     hasWriteObjectMethod = serializable ?
  596.         (flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0 :
  597.         false;
  598.  
  599.     /* MOVED from ObjectStreamConstants, due to failing SignatureTest.
  600.          * In JDK 1.2, SC_BLOCK_DATA is a constant in ObjectStreamConstants.
  601.      * If SC_EXTERNALIZABLE, this bit indicates externalizable data 
  602.      * written in block data mode. */
  603.         final byte SC_BLOCK_DATA = 0x08;  
  604.  
  605.     hasExternalizableBlockData = externalizable ? 
  606.         (flags & SC_BLOCK_DATA) != 0 :
  607.         false;
  608.  
  609.     /* Read the number of fields described.
  610.      * For each field read the type byte, the name.
  611.      */    
  612.     int count = s.readShort();
  613.     fields = new ObjectStreamField[count];
  614.  
  615.     /* disable replacement of String objects written
  616.      * by ObjectStreamClass. */
  617.     boolean prevEnableResolve = s.enableResolve;
  618.     s.enableResolve = false;
  619.     try {
  620.         for (int i = 0; i < count; i++ ) {
  621.         char type = (char)s.readByte();
  622.         String name = s.readUTF();
  623.         String ftype = null;
  624.         if (type == '[' || type == 'L') {
  625.             ftype = (String)s.readObject();
  626.         }
  627.         fields[i] = new ObjectStreamField(name, type, -1, ftype);
  628.         }
  629.     } finally {
  630.         s.enableResolve = prevEnableResolve;
  631.     }
  632.     }
  633.  
  634.  
  635.     /*
  636.      * Cache of Class -> ClassDescriptor Mappings.
  637.      */
  638.     static private ObjectStreamClassEntry[] descriptorFor = new ObjectStreamClassEntry[61];
  639.  
  640.     /*
  641.      * findDescriptorFor a Class.
  642.      * This looks in the cache for a mapping from Class -> ObjectStreamClass mappings.
  643.      * The hashCode of the Class is used for the lookup since the Class is the key.
  644.      * The entries are extended from sun.misc.Ref so the gc will be able to free them
  645.      * if needed.
  646.      */
  647.     private static ObjectStreamClass findDescriptorFor(Class cl) {
  648.  
  649.     int hash = cl.hashCode();
  650.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  651.     ObjectStreamClassEntry e;
  652.     ObjectStreamClassEntry prev;
  653.     
  654.     /* Free any initial entries whose refs have been cleared */
  655.     while ((e = descriptorFor[index]) != null && e.check() == null) {
  656.         descriptorFor[index] = e.next;
  657.     }
  658.  
  659.     /* Traverse the chain looking for a descriptor with ofClass == cl.
  660.      * unlink entries that are unresolved.
  661.      */
  662.     prev = e;
  663.     while (e != null ) {
  664.         ObjectStreamClass desc = (ObjectStreamClass)(e.check());
  665.         if (desc == null) {
  666.         // This entry has been cleared,  unlink it
  667.         prev.next = e.next;
  668.         } else {
  669.         if (desc.ofClass == cl)
  670.             return desc;
  671.         prev = e;
  672.         }
  673.         e = e.next;
  674.     }
  675.     return null;
  676.     }
  677.  
  678.     /*
  679.      * insertDescriptorFor a Class -> ObjectStreamClass mapping.
  680.      */
  681.     private static void insertDescriptorFor(ObjectStreamClass desc) {
  682.     // Make sure not already present
  683.     if (findDescriptorFor(desc.ofClass) != null) {
  684.         return;
  685.     }
  686.  
  687.     int hash = desc.ofClass.hashCode();
  688.     int index = (hash & 0x7FFFFFFF) % descriptorFor.length;
  689.     ObjectStreamClassEntry e = new ObjectStreamClassEntry();
  690.     e.setThing(desc);
  691.     e.next = descriptorFor[index];
  692.            descriptorFor[index] = e;
  693.     }
  694.  
  695.     /*
  696.      * The name of this descriptor
  697.      */
  698.     private String name;
  699.     
  700.     /*
  701.      * The descriptor of the supertype.
  702.      */
  703.     private ObjectStreamClass superclass;
  704.  
  705.     /*
  706.      * Flags for Serializable and Externalizable.
  707.      */
  708.     private boolean serializable;
  709.     private boolean externalizable;
  710.     
  711.     /*
  712.      * Array of persistent fields of this class, sorted by
  713.      * type and name.
  714.      */
  715.     private ObjectStreamField[] fields;
  716.     
  717.     /*
  718.      * Class that is a descriptor for in this virtual machine.
  719.      */
  720.     private Class ofClass;
  721.     
  722.     /* 
  723.      * SerialVersionUID for this class.
  724.      */
  725.     private long suid;
  726.     
  727.     /*
  728.      * This sequence of type, byte offset of the fields to be
  729.      * serialized and deserialized.
  730.      */
  731.     private int[] fieldSequence;
  732.  
  733.     /* True if this class has/had a writeObject method */
  734.     private boolean hasWriteObjectMethod;
  735.     
  736.     /* In JDK 1.1, external data was not written in block mode.
  737.      * As of JDK 1.2, external data is written in block data mode. This
  738.      * flag enables JDK 1.1.6 to distinguish between JDK 1.1 external
  739.      * data format and JDK 1.2 external data format.
  740.      *
  741.      * @since JDK 1.1.6
  742.      */
  743.     private boolean hasExternalizableBlockData;
  744.  
  745.     /*
  746.      * ObjectStreamClass that this one was built from.
  747.      */
  748.     private ObjectStreamClass localClassDesc;
  749.     
  750.     /* Get the array of non-static and non-transient fields */
  751.     private native ObjectStreamField[] getFields0(Class cl);
  752.     
  753.     /* Get the serialVersionUID from the specified class */
  754.     private static native long getSerialVersionUID(Class cl);
  755.     
  756.     /* Get the boolean as to whether the class has/had a writeObject method. */
  757.     private static native boolean hasWriteObject(Class cl);
  758.     
  759.     /* The Class Object for java.io.Serializable */
  760.     private static Class classSerializable = null;
  761.     private static Class classExternalizable = null;
  762.  
  763.     /*
  764.      * Resolve java.io.Serializable at load time.
  765.      */
  766.     static {
  767.     try {
  768.         classSerializable = Class.forName("java.io.Serializable");
  769.         classExternalizable = Class.forName("java.io.Externalizable");
  770.     } catch (Throwable e) {
  771.         System.err.println("Could not load java.io.Serializable or java.io.Externalizable.");
  772.     }
  773.     }
  774.  
  775.     /* Support for quicksort */
  776.  
  777.     /*
  778.      * Implement the doCompare method.
  779.      * Strings are compared directly.
  780.      * Classes are compared using their names.
  781.      * ObjectStreamField objects are compared by type and name
  782.      * and then their descriptors (as strings).
  783.      */
  784.     private static int doCompare(Object o1, Object o2) {
  785.     String s1, s2;
  786.     if (o1 instanceof String && o2 instanceof String) {
  787.         s1 = (String)o1;
  788.         s2 = (String)o2;
  789.     } else if (o1 instanceof Class && o2 instanceof Class) {
  790.         Class c1 = (Class)o1;
  791.         Class c2 = (Class)o2;
  792.         s1 = c1.getName();
  793.         s2 = c2.getName();
  794.     } else if (o1 instanceof ObjectStreamField &&
  795.            o2 instanceof ObjectStreamField) {
  796.         ObjectStreamField f1 = (ObjectStreamField)o1;
  797.         ObjectStreamField f2 = (ObjectStreamField)o2;
  798.         s1 = f1.name;
  799.         s2 = f2.name;
  800.     } else {
  801.         throw new Error("Unsupported types");
  802.     }
  803.     return s1.compareTo(s2);
  804.     }
  805.  
  806.     private static void swap(Object arr[], int i, int j) {
  807.     Object tmp;
  808.  
  809.     tmp = arr[i];
  810.     arr[i] = arr[j];
  811.     arr[j] = tmp;
  812.     }
  813.  
  814.     /*
  815.      * quicksort the array of objects.
  816.      *
  817.      * @param arr[] - an array of objects
  818.      * @param left - the start index - from where to begin sorting
  819.      * @param right - the last index.
  820.      */
  821.     private static void quicksort(Object arr[], int left, int right)
  822.     {
  823.     int i, last;
  824.  
  825.     if (left >= right) { /* do nothing if array contains fewer than two */
  826.         return;          /* two elements */
  827.     }
  828.     swap(arr, left, (left+right) / 2);
  829.     last = left;
  830.     for (i = left+1; i <= right; i++) {
  831.         if (doCompare(arr[i], arr[left]) < 0) {
  832.         swap(arr, ++last, i);
  833.         }
  834.     }
  835.     swap(arr, left, last);
  836.     quicksort(arr, left, last-1);
  837.     quicksort(arr, last+1, right);
  838.     }
  839.  
  840.     /*
  841.      * Preform a sort using the specified comparitor object.
  842.      */       
  843.     private static void quicksort(Object arr[]) {
  844.         quicksort(arr, 0, arr.length-1);
  845.     }
  846. }
  847.  
  848.  
  849. /*
  850.  * Entries held in the Cache of known ObjectStreamClass objects.
  851.  * Entries are chained together with the same hash value (modulo array size).
  852.  */
  853. class ObjectStreamClassEntry extends sun.misc.Ref {
  854.     ObjectStreamClassEntry next;
  855.     public Object reconstitute() {
  856.     return null;
  857.     }
  858. }
  859.